import org.apache.commons.math3.optim.MaxEval;
import org.apache.commons.math3.optim.PointValuePair;
import org.apache.commons.math3.optim.linear.LinearConstraint;
import org.apache.commons.math3.optim.linear.LinearConstraintSet;
import org.apache.commons.math3.optim.linear.LinearObjectiveFunction;
import org.apache.commons.math3.optim.linear.NonNegativeConstraint;
import org.apache.commons.math3.optim.linear.Relationship;
import org.apache.commons.math3.optim.linear.SimplexSolver;
import org.apache.commons.math3.optim.nonlinear.scalar.GoalType;

import java.util.ArrayList;
import java.util.List;

public class DynamicPlanFormulation {

    public static void main(String[] args) {
        try{
            // 原料数量
            int numIngredients = 3;
            // 营养指标数量
            int numNutrients = 2;

            // 原料单价 (元/吨)
            double[] prices = {1200, 1500, 2000};

            // 原料营养成分含量 (每千克原料的营养成分含量)
            double[][] nutrientContents = {
                    {3.24, 0.087}, // 玉米: 代谢能, 粗蛋白
                    {2.0, 0.15},   // 麦麸: 代谢能, 粗蛋白
                    {8.0, 0.0}     // 大豆油: 代谢能, 粗蛋白
            };

            // 营养指标下限
            double[] nutrientLowerBounds = {2.75, 0.17};
            // 营养指标上限
            double[] nutrientUpperBounds = {2.85, 0.18};

            // 原料使用比例下限
            double[] ingredientLowerBounds = {0.6, 0.1, 0.0};
            // 原料使用比例上限
            double[] ingredientUpperBounds = {0.9, 0.3, 0.1};

            // 构建目标函数
            LinearObjectiveFunction objective = new LinearObjectiveFunction(prices, 0);

            // 构建约束条件
            List<LinearConstraint> constraints = new ArrayList<>();

            // 营养指标约束
            for (int i = 0; i < numNutrients; i++) {
                double[] coefficients = new double[numIngredients];
                for (int j = 0; j < numIngredients; j++) {
                    coefficients[j] = nutrientContents[j][i];
                }
                constraints.add(new LinearConstraint(coefficients, Relationship.GEQ, nutrientLowerBounds[i]));
                constraints.add(new LinearConstraint(coefficients, Relationship.LEQ, nutrientUpperBounds[i]));
            }

            // 原料比例约束
            for (int i = 0; i < numIngredients; i++) {
                double[] lowerCoefficients = new double[numIngredients];
                lowerCoefficients[i] = 1;
                constraints.add(new LinearConstraint(lowerCoefficients, Relationship.GEQ, ingredientLowerBounds[i]));

                double[] upperCoefficients = new double[numIngredients];
                upperCoefficients[i] = 1;
                constraints.add(new LinearConstraint(upperCoefficients, Relationship.LEQ, ingredientUpperBounds[i]));
            }

            // 比例总和约束
            double[] sumCoefficients = new double[numIngredients];
            for (int i = 0; i < numIngredients; i++) {
                sumCoefficients[i] = 1;
            }
            constraints.add(new LinearConstraint(sumCoefficients, Relationship.EQ, 1));

            // 求解线性规划问题
            SimplexSolver solver = new SimplexSolver();
            PointValuePair solution = solver.optimize(
                    new MaxEval(100),
                    objective,
                    new LinearConstraintSet(constraints),
                    GoalType.MINIMIZE,
                    new NonNegativeConstraint(true)
            );

            // 输出结果
            double[] optimalSolution = solution.getPoint();
            System.out.println("最低成本: " + solution.getValue() + " 元/吨");
            for (int i = 0; i < numIngredients; i++) {
                System.out.println("原料 " + (i + 1) + " 比例: " + optimalSolution[i]);
            }
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }
}